/*
 * This file is part of GuitarMaster.
 * 
 * GuitarMaster is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GuitarMaster is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with GuitarMaster.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.paris5.master2.guitarmaster.dao;

/*
 * $Id: EcomDaoService.java 61 2013-04-06 11:34:53Z sarreyah@gmail.com $
 * 
 * $HeadURL: https://com-paris5-master2-guitarmaster-ejb.googlecode.com/svn/trunk/com.paris5.master2.guitarmaster-ejb/src/java/com/paris5/master2/guitarmaster/dao/EcomDaoService.java $
 * $Revision: 61 $
 * $Date: 2013-04-06 13:34:53 +0200 (sam., 06 avr. 2013) $
 * $Author: sarreyah@gmail.com $
 */

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.Parameter;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import com.paris5.master2.guitarmaster.exception.EcomQueryException;

/**
 * @author Leticia Mahamed, Alice Khammy, mourad nedjahi, Saliou Mamadou Barry
 * 
 * Data access Object
 */
@Stateless
public class EcomDaoService implements EcomDao{
    
    @PersistenceContext private EntityManager em;
    
    @Override
    public void insert(Object obj) {
        em.persist(obj);
        em.flush();
	em.refresh(obj);
 
        //LOG.info("CREATION PERSON ID : "+obj.toString());
    }

    @Override
    public void update(Object obj) {
        em.merge(obj);
       
        //em.flush();
    }

    @Override
    public void delete(Object obj) {
        em.remove(obj);
    }

    @Override
    public Object find(Class c, Object id) {
        Object o = em.find(c, id);
        em.flush();
        return o;
    }
    
    @Override
    public Object execute(String method, Map<String, Object> parameters) throws EcomQueryException {
        Query query = em.createNamedQuery(method);
        query = buildQuery(query, parameters, 0, 1);
        return query.getSingleResult();
    }
    
    @Override
    public List<Object> execute(String method, Map<String, Object> parameters, int offset, int limit) throws EcomQueryException {
        Query query = em.createNamedQuery(method);
        query = buildQuery(query, parameters, offset, limit);
        return query.getResultList();
    }
    
    @Override
    public Object execute(String eq, List<Object> values) throws EcomQueryException {
        Query query = em.createNamedQuery(eq);
        query = buildQuery(query, values, 0, 1);
        try{
            return query.getSingleResult();
        }
        catch(Exception e){
            return null;
        }
    }
    
    @Override
    public List<Object> execute(String eq, List<Object> values, int offset, int limit) throws EcomQueryException {
        Query query = em.createNamedQuery(eq);
        query = buildQuery(query, values, offset, limit);
        return query.getResultList();
    }

    @Override
    public Object execute(EcomQuery eq, List<Object> values) throws EcomQueryException {
        Query query = em.createQuery(eq.getQuery());
        query = buildQuery(query, values, 0, 1);
        try{
            return query.getSingleResult();
        }
        catch(Exception e){
            return null;
        }
    }

    @Override
    public List<Object> execute(EcomQuery eq, List<Object> values, int offset, int limit) throws EcomQueryException {
        Query query = em.createQuery(eq.getQuery());
        query = buildQuery(query, values, offset, limit);
        return query.getResultList();
    }
    
    @Override
    public List<Object> findAll(Class bean, int offset, int limit){       
        CriteriaBuilder qb = em.getCriteriaBuilder();
        CriteriaQuery cq = qb.createQuery();
        cq.select(cq.from(bean));
        return (List<Object>) em.createQuery(cq).setFirstResult(offset).setMaxResults(limit).getResultList();
    }

    @Override
    public int countAll(Class entity) {
        CriteriaBuilder qb = em.getCriteriaBuilder();
        CriteriaQuery cq = qb.createQuery();
        cq.select(qb.count(cq.from(entity)));
        Long res = (Long) em.createQuery(cq).getSingleResult();
        if(res!=null){
            return res.intValue();
        }
        
        return 0;
    }
    
    ///////////////////////////
    // Privates
    //////////////////////////
    
    private Query buildQuery(Query query, List<Object> values, int offset, int limit) throws EcomQueryException {
        
        Set<Parameter<?>> bindings = query.getParameters();
        if(bindings.size() != values.size()){
            throw new EcomQueryException(query.toString(), values.size()+" != "+bindings.size());
        }
        
        for (int i = 0; i < bindings.size(); i++) {
            query.setParameter(i+1, values.get(i));
        }
        
        if(limit!=0 && limit > offset){
            query.setFirstResult(offset).setMaxResults(limit);
        }

        return query;
    }
    
    public Query buildQuery(Query query, Map<String, Object> parameters, int offset, int limit) throws EcomQueryException {
        
        Set<Parameter<?>> queryParams = query.getParameters();
        
        Parameter<?> bind;
        boolean error=false;
        Iterator it = queryParams.iterator();
        
        while(!error && it.hasNext()){
            
            bind = (Parameter<?>) it.next();
            
            if(parameters.get(bind.getName())==null){
                error = true;
            }
            else{
                query.setParameter(bind.getName(), parameters.get(bind.getName()));
            }
        }
        
        if(limit!=0 && limit > offset){
            query.setFirstResult(offset).setMaxResults(limit);
        }
        
        if(error){
            throw new EcomQueryException(query.toString(), parameters.toString());
        }
        
        return query;
    }
}